﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.Sockets.Core;
using System.Net.Sockets;
using Pixysoft.Framework.Verifications;
using Pixysoft.Framework.Sockets.Controller;
using Pixysoft.Tools;
using System.Threading;
using Pixysoft.Framework.Sockets.Codec;

namespace Pixysoft.Framework.Sockets
{
    public class SocketManager
    {
        string ip;
        int port = -1;

        ISessionCodecFactory codec = new SocketSessionCodecFactory();
        IActionHandlerCallback generalCallback = null;
        ActionHandlerCallbackFactory callbacks = new ActionHandlerCallbackFactory();
        SyncSendController syncSends = new SyncSendController();

        ClientSocketIoSession session = null;
        public event SocketExceptionCaught OnSocketExceptionCaught;

        public static void Initialize(SocketConfiguration config)
        {
            SettingHelper.Initialize(config);
        }

        public SocketManager(string ip, int port, IActionHandlerCallback generalCallback)
            : this(ip, port, new SocketSessionCodecFactory(), generalCallback)
        {
        }

        public SocketManager(string ip, int port, ISessionCodecFactory codec, IActionHandlerCallback generalCallback)
        {
            this.ip = ip;
            this.port = port;
            this.codec = codec;
            this.generalCallback = generalCallback;
        }

        public bool RegisterCallback(IActionHandlerCallback callback)
        {
            ProtocolDeclaration declaration = Pixysoft.Reflection.ReflectHelper.Instance.GetCustomerAttribute<
                ProtocolDeclaration>(callback.GetType());

            if (declaration == null)
                throw Exceptions.ManualVerificationFailedException("no annotaion for " + callback.GetType().Name);

            return callbacks.RegisterCallback(declaration.Protocol, declaration.Action, callback);

        }

        public bool RegisterCallback(int protocol, int action, IActionHandlerCallback callback)
        {
            return callbacks.RegisterCallback(protocol, action, callback);
        }

        public void ClearCallbacks()
        {
            callbacks.ClearCallbacks();
        }

        /// <summary>
        /// 链接并进入接受模式
        /// </summary>
        /// <returns></returns>
        public bool Connect()
        {
            Disconnect();

            TcpClient client = new TcpClient();

            try
            {
                client.Connect(ip, port);
            }
            catch (Exception ex)
            {
                LoggerHelper.Fatal(ex);

                return false;
            }

            session = ClientSocketIoSession.CreateSession(codec.CreateEncoder(), codec.CreateDecoder(), client.Client);

            session.OnSocketExceptionCaught += new SocketExceptionCaught(session_OnSocketExceptionCaught);

            session.OnSocketMessageReceived += new SocketMessageReceived(session_OnSocketMessageReceived);

            return true;
        }

        public void Disconnect()
        {
            if (session != null)
            {
                session.Close();
                session.Dispose();
            }

            session = null;
        }

        public bool IsConnected
        {
            get
            {
                if (session == null)
                    return false;

                return !session.IsDisposed;
            }
        }

        public void Send(IProtocolMessage message)
        {
            if (!IsConnected)
                throw Exceptions.UnexpectedResultException("socket connection is closed.");

            session.Send(message);
        }

        public void Send(IProtocolMessage[] messages)
        {
            if (!IsConnected)
                throw Exceptions.UnexpectedResultException("socket connection is closed.");

            session.Send(messages);
        }

        public void Send(byte[] sendBytes)
        {
            if (!IsConnected)
                throw Exceptions.UnexpectedResultException("socket connection is closed.");

            session.Send(sendBytes);
        }

        /// <summary>
        /// 同步发送请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="message"></param>
        /// <returns></returns>
        public IProtocolMessage SyncSend(IProtocolMessage message)
        {
            if (!IsConnected)
                throw Exceptions.UnexpectedResultException("socket connection is closed.");

            DateTime requestTime = GlobalTimer.Instance.GetGlobalTime();

            //注册回调接口

            syncSends.PushCallback(message);

            //发送请求

            Send(message);

            //回调接口触发，修改状态

            bool iscompleted = false;

            do
            {
                Thread.Sleep(100);

                iscompleted = syncSends.IsCompleted(message);

                if (iscompleted)
                    break;
            }
            while (requestTime.AddMilliseconds(SettingHelper.default_interval_sync_send) > GlobalTimer.Instance.GetGlobalTime());

            //返回回调接口的返回对象

            IProtocolMessage response = syncSends.PopCallback(message);

            if (!iscompleted)
            {
                throw Exceptions.UnexpectedResultException("sync send request timeout. {0}.{1}",
                    message.Protocol, message.Action);
            }

            return response;
        }

        public IProtocolMessage CreateRequest(int protocol, int action)
        {
            if (!IsConnected)
                throw Exceptions.UnexpectedResultException("socket connection is closed.");

            return session.CreateRequest(protocol, action);
        }

        public IProtocolMessage CreateResponse(IProtocolHeader header)
        {
            if (!IsConnected)
                throw Exceptions.UnexpectedResultException("socket connection is closed.");

            return session.CreateResponse(header);
        }



        /// <summary>
        /// 异常回调
        /// </summary>
        /// <param name="session"></param>
        /// <param name="ex"></param>
        private void session_OnSocketExceptionCaught(ISocketIoSession session, Exception ex)
        {
            if (this.OnSocketExceptionCaught != null)
                OnSocketExceptionCaught(session, ex);
        }

        /// <summary>
        /// 接受信息
        /// </summary>
        /// <param name="messages"></param>
        private void session_OnSocketMessageReceived(ISocketIoSession session, IProtocolMessage[] messages)
        {
            foreach (IProtocolMessage message in messages)
            {
                //先查看压入的同步调用堆栈 如果有 直接处理

                if (syncSends.HasCallback(message))
                {
                    syncSends.Callback(message);

                    continue;
                }


                //异步调用处理

                IActionHandlerCallback command = callbacks.TryGetCallback(
                    message.Protocol,
                    message.Action);

                if (command == null)
                {
                    if (this.generalCallback != null)
                    {
                        generalCallback.Callback(session, message, message.ByteBody);
                    }
                    else
                    {
                        LoggerHelper.Error("missing callback for protocol:{0} action:{1}", message.Protocol, message.Action);
                    }
                }
                else
                {
                    command.Callback(session, message, message.ByteBody);
                }
            }
        }
    }
}
